package com.dd.cloud.user.service.classroom.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.user.config.MediaConfig;
import com.dd.cloud.common.constants.ClassroomConstants;
import com.dd.cloud.user.entity.classroom.MediaContent;
import com.dd.cloud.user.entity.classroom.MediaSection;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.user.mapper.classroom.MediaContentMapper;
import com.dd.cloud.user.req.classroom.CreateMediaContentReq;
import com.dd.cloud.user.req.classroom.UploadMediaContentListReq;
import com.dd.cloud.user.res.classroom.MediaContentDetailRes;
import com.dd.cloud.user.service.classroom.IMediaContentService;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.constants.FileConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.FileUtil;
import com.dd.cloud.common.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 媒体内容表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-09-14
 */
@Service
@Slf4j
public class MediaContentServiceImpl extends ServiceImpl<MediaContentMapper, MediaContent> implements IMediaContentService {

    @Autowired
    public MediaConfig mediaConfig;


    /**
     * 查询小节的所有视频
     *
     * @param sectionId
     * @return
     */
    @Override
    public List<MediaContentDetailRes> getMediaContentList(Integer sectionId, Integer classifyId) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        List<MediaContentDetailRes> list = getBaseMapper().queryMediaContentList(loginInfo.getId(), loginInfo.getType(), sectionId, classifyId);
        list.stream().forEach(mo -> {
            if (!StringUtils.isBlank(mo.getPlayUrl())) {
                mo.setPlayUrl(mediaConfig.getMediaPlay() + mo.getPlayUrl());
            }
        });

        return list;
    }

    /**
     * 批量添加
     *
     * @param list
     */
    @Override
    public void insertBatch(List<MediaContent> list) {
        Integer flag = getBaseMapper().insertBatchSomeColumn(list);
        if (flag <= 0) {
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 单视频小节上传
     *
     * @param req
     * @param section 视频内容
     * @param valid   是否是验证参数 0验证(只验证不操作) 1操作
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadMedia(UploadMediaContentListReq req, MediaSection section, Integer valid) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        MediaContent content;

        if (req.getId() != null) {
            content = getById(req.getId());
            if (content == null) {
                content = new MediaContent();
            }
        } else {
            content = new MediaContent();
        }

        if (content.getId() != null && !StringUtils.isBlank(req.getName()) && req.getName().equals(content.getName())) {
            //修改了视频名, 查询是否重复名
            if (checkMediaNameExists(section.getId(), req.getName())) {
                return "视频名称已存在:" + req.getName();
                //throw new ZekeException(400, "视频名称已存在:" + req.getName());
            }

        }
        if (content.getId() == null) {
            //新增的视频, 检查视频名
            if (checkMediaNameExists(section.getId(), req.getName())) {
                return "视频名称已存在:" + req.getName();
//                throw new ZekeException(400, "视频名称已存在:" + req.getName());
            }
            //id为空, 文件也为空, 即为测试参数不做处理
            if (req.getFile() == null) {
                return null;
            }
        }
        /**
         * 效验参数, 退出
         */
        if (valid == 0) {
            return null;
        }
        MultipartFile file = null;
        String fileName = null;
        /**
         * 有文件就去上传, 没文件修改数据即可
         */
        if (req.getFile() != null) {
            file = req.getFile();
            log.info(file.getContentType());
            if (!Arrays.asList(FileConstants.Format.MEDIA).contains(file.getContentType())) {
                throw new ZekeException(ZkExceptionEnum.CONTENT_TYPE_ERROE);
            }
            //下载的文件名
            fileName = file.getOriginalFilename();
            content.setMediaName(fileName);
            content.setUrl("vod/" + section.getName() + "/" + fileName + "/index.m3u8");
            content.setFileUrl(section.getName() + "/" + fileName);
            long duration = 0;
            try {
                CommonsMultipartFile cf = (CommonsMultipartFile) file;

            } catch (Exception e) {
                return " 视频时长获取失败:" + req.getName();
//                throw new ZekeException(400, "视频时长获取失败:" + req.getName());
            }
            if (duration <= 1) {
                return " 视频小于1秒, 不能上传:" + file.getOriginalFilename();
//                throw new ZekeException(400, "视频小于1秒, 不能上传:" + file.getOriginalFilename());
            }
            if (!FileUtil.checkFileSize(file.getSize(), FileConstants.mediaMaxSize, FileConstants.SizeUnit.MB)) {
                return " 视频大于" + FileConstants.mediaMaxSize + "M, 不能上传:" + file.getOriginalFilename();
//                throw new ZekeException(400, "视频大于" + FileConstants.mediaMaxSize + "M, 不能上传:" + file.getOriginalFilename());
            }
            content.setDuration(duration);
            content.setSize(FileUtil.readableFileSize(file.getSize()));
        }

        int sort = cumSectionSort(section.getId(), req.getSort());
        content.setSort(sort);
        if (StringUtils.isBlank(req.getName())) {
            content.setName("第" + sort + "节");
        } else {
            content.setName(req.getName());
        }

        content.setStatus(ClassroomConstants.ContentStatus.NORMAL);
        content.setSectionId(section.getId());
        if (content.getId() != null) {
            content.setUpdateId(loginInfo.getId());
        } else {
            content.setCreateId(loginInfo.getId());
        }
        int flag = 0;
        if (content.getId() == null) {
            flag = getBaseMapper().insert(content);
        } else {
            flag = getBaseMapper().updateById(content);
        }
        if (flag <= 0) {
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
        log.info(content.toString());
        if (file != null) {
            try {
                file.transferTo(new File(mediaConfig.getMediaAddr() + section.getName() + File.separator + fileName));
            } catch (Exception e) {
                return " 视频写入失败:" + req.getName();
//                throw new ZekeException(400, "视频写入失败:" + req.getName());
            }
        }
        return null;
    }

    /**
     * 查询视频名是否存在
     *
     * @param sectionId
     * @param name
     * @return
     */
    @Override
    public boolean checkMediaNameExists(Integer sectionId, String name) {
        QueryWrapper<MediaContent> qw = new QueryWrapper<>();
        qw.lambda().eq(MediaContent::getSectionId, sectionId)
                .eq(MediaContent::getName, name)
                .ne(MediaContent::getStatus, ClassroomConstants.ContentStatus.DEL);
        int num = count(qw);
        return num == 0 ? false : true;
    }

    /**
     * 列表中查询已存在的视频名
     *
     * @param sectionId 小节id
     * @param listName  名字列表
     * @return
     */
    @Override
    public List<String> checkMediaNameExists(Integer sectionId, List<String> listName) {
        QueryWrapper<MediaContent> qw = new QueryWrapper<>();
        qw.lambda().eq(MediaContent::getSectionId, sectionId)
                .ne(MediaContent::getStatus, ClassroomConstants.ContentStatus.DEL)
                .in(MediaContent::getName, listName);
        List<MediaContent> list = list(qw);
        return list.stream().map(MediaContent::getName).collect(Collectors.toList());
    }

    /**
     * 添加或修改视频时验证视频名
     *
     * @param mediaList
     */
    @Override
    public void addOrUpdateCheackMediaName(List<CreateMediaContentReq> mediaList, Integer sectionId) {
        if (mediaList == null || mediaList.isEmpty()) {
            return;
        }
        for (CreateMediaContentReq req :
                mediaList) {
            MediaContent content;
            if (req.getId() != null) {
                content = getById(req.getId());
                if (content == null) {
                    throw new ZekeException(400, "视频id不存在:" + req.getId());
                }
            } else {
                content = new MediaContent();
            }
            if (content.getId() != null && !StringUtils.isBlank(req.getName()) && req.getName().equals(content.getName())) {
                //修改了视频名, 查询是否重复名
                if (checkMediaNameExists(sectionId, req.getName())) {
                    throw new ZekeException(400, "视频名已存在:" + req.getName());
                }
            }
            if (content.getId() == null) {
                //新增的视频, 检查视频名
                if (checkMediaNameExists(sectionId, req.getName())) {
                    throw new ZekeException(400, "视频名已存在" + req.getName());
                }
            }
        }
    }

    /**
     * 修改视频状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateContentStatus(Integer id, Integer status) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        MediaContent mediaContent = getById(id);
        if (mediaContent == null || mediaContent.getStatus() == ClassroomConstants.ContentStatus.DEL) {
            throw new ZekeException(400, "视频不存在");
        }
        if (!ObjectUtils.refrect(ClassroomConstants.ContentStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        if (mediaContent.getStatus().equals(status)) {
            return;
        }
        if (mediaContent.getStatus() == ClassroomConstants.ContentStatus.RELETED && status == ClassroomConstants.ContentStatus.NORMAL) {
            throw new ZekeException(400, "启用视频无效,该视频大类或视频内容未启用");
        }
        mediaContent.setStatus(status);
        boolean flag = updateById(mediaContent);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
        //删除文件
        if (status == ClassroomConstants.ContentStatus.DEL) {
            try {
                File file = new File(mediaConfig.getMediaAddr() + mediaContent.getFileUrl());
                file.delete();
            } catch (Exception e) {
                log.info("删除文件失败");
            }
        }
    }

    /**
     * 修改大类下所有小节的状态, 连带操作,比如禁用/删除了大类或小节, 大类下的视频都要禁用/删除
     *
     * @param classifyId
     * @param status
     */
    @Override
    public void updateContentStatusByClassify(Integer classifyId, Integer status) {
        if (!ObjectUtils.refrect(ClassroomConstants.ContentStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        //删除文件
        List<MediaContentDetailRes> list = null;
        if (status == ClassroomConstants.ContentStatus.DEL) {
            list = getMediaContentList(null, classifyId);
        }

        getBaseMapper().updateContentStatusByClassifyId(classifyId, status);
        //删除文件
        if (status != ClassroomConstants.ContentStatus.DEL) {
            return;
        }

        if (list == null || list.isEmpty()) {
            return;
        }
        for (MediaContentDetailRes res :
                list) {
            try {
                File file = new File(mediaConfig.getMediaAddr() + res.getFileUrl());
                file.delete();
            } catch (Exception e) {
                log.info("删除文件失败");
            }
        }

    }

    /**
     * 修改小节的状态, 连带操作,比如禁用/删除了小节, 大类下的视频都要禁用/删除
     *
     * @param sectionId
     * @param status
     */
    @Override
    public void updateContentStatusBySection(Integer sectionId, Integer status) {
        if (!ObjectUtils.refrect(ClassroomConstants.ContentStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        //删除文件
        List<MediaContentDetailRes> list = null;
        if (status == ClassroomConstants.ContentStatus.DEL) {
            list = getMediaContentList(sectionId, null);
        }

        UpdateWrapper<MediaContent> uw = new UpdateWrapper<>();
        uw.lambda().set(MediaContent::getStatus, status)
                .in(MediaContent::getStatus, new Integer[]{ClassroomConstants.ContentStatus.NORMAL, ClassroomConstants.ContentStatus.RELETED})
                .eq(MediaContent::getSectionId, sectionId);
        update(uw);
        //删除文件
        if (status != ClassroomConstants.ContentStatus.DEL) {
            return;
        }

        if (list == null || list.isEmpty()) {
            return;
        }
        for (MediaContentDetailRes res :
                list) {
            try {
                File file = new File(mediaConfig.getMediaAddr() + res.getFileUrl());
                file.delete();
            } catch (Exception e) {
                log.info("删除文件失败");
            }
        }
    }

    /**
     * 视频重排序
     *
     * @param sort      排序位置
     * @param sectionId 小节id
     * @return 目标位置
     */
    public int cumSectionSort(Integer sectionId, Integer sort) {
        //先进行重排序
        getBaseMapper().updateMediaContentReorder(sectionId);
        if (sort == null) {
            QueryWrapper<MediaContent> qu = new QueryWrapper<>();
            qu.lambda().eq(MediaContent::getSectionId, sectionId)
                    .orderByDesc(MediaContent::getSort)
                    .last("limit 1");
            MediaContent content = getOne(qu);
            if (content == null) {
                return 1;
            }
            return content.getSort() + 1;
        }
        UpdateWrapper<MediaContent> uw = new UpdateWrapper<>();
        uw.lambda().ge(MediaContent::getSort, sort)
                .eq(MediaContent::getSectionId, sectionId)
                .setSql("`sort` = `sort` + 1");
        update(uw);
        return sort;
    }

}
